/**
 * 这里面放权限相关的内容
 * 这里的权限指的是前端权限,所以org放在这里
 * 注意,关于token并没有放在这里,而是放在了sessionStorage中
 */

import {menuGroup, menuType} from '@/view/auth/dict'
import router, {constantRoutes, dynamicRoutes} from '@/router/index.js'
import {hasToken} from '@/permission/permission.js'
import userApi from '@/api/auth/userApi'
import {yesOrNo} from '@/common/dict'
import store from '@/store/index'
import cache from '@/cache/index'

// 是否允许无效路由的注册...
const ALLOW_INVALID_MENU = false

const menuTypeEnum = menuType.enum

function isHomePage(route) {
  if (route.path === store.getters['system/homePage']) {
    return true
  }
}

function stateBuilder() {
  return {
    // 用户可访问的路由信息,直接存在路由表里就好了,这里做了冗余,直接删掉即可
    routes: [],
    // 用户可访问的菜单信息
    menus: [],
    // 用户可访问的按钮信息
    buttons: [],
    // 权限是否构建完成
    perCompleted: false,
    // 当前激活的路由
    activeRoute: {},
    // 当前打开的路由
    openedRoutes: [],
    // 当前子系统
    currentSystem: 'home',
    // 需要缓存的路由
    cachedRoutes: [],
  }
}

export default {
  // 使用命名空间,规范调用,便于区分功能,也避免命名重复
  namespaced: true,
  state: stateBuilder(),
  getters: {
    openedComponentNames: (state) => {
      return state.openedRoutes.map(route => route.meta.name)
    },
    activeRouteCode: (state) => {
      return state.activeRoute.meta.code
    },
    getButtons: (state) => (code) => {
      return state.buttons[code] || []
    },
  },
  mutations: {
    setMenus(state, menus) {
      state.menus = menus
    },
    setButtons(state, buttons) {
      state.buttons = buttons
    },
    setRoutes(state, routes) {
      state.routes = routes
    },
    setPerCompleted(state, perCompleted) {
      state.perCompleted = perCompleted
    },
    setActiveRoute(state, route) {
      state.activeRoute = route
    },
    addOpenedRoutes(state, route) {
      if (!~state.openedRoutes.findIndex(e => e.meta.code === route.meta.code)) {
        state.openedRoutes.push(route)
      }
    },
    // 增加需要缓存的路由名称
    addCachedRoutes(state, route) {
      if (route.name && route.meta.cached && !~state.cachedRoutes.indexOf(route.name)) {
        state.cachedRoutes.push(route.name)
      }
    },
    // 删除某个缓存的路由名称
    delCacheRoutes(state, routes) {
      routes.forEach(route => {
        let index = state.cachedRoutes.indexOf(route.name)
        if (~index) {
          state.cachedRoutes.splice(index, 1)
        }
      })
    }
  },
  // action可以是异步的
  actions: {
    init(context, data) {
      return new Promise((resolve, reject) => {
        const _hasToken = hasToken()
        // 用户可访问的菜单,树状结构
        let constantMenus = []
        let dynamicMenus = []
        // 用户可访问的路由,列表结构
        let constantRoutes = []
        let dynamicRoutes = []
        // 用户可访问的按钮,对象的形式存储
        let constantButtons = {}
        let dynamicButtons = {}
        // 初始的路由表是空的,不管有没有登陆都需要获取固定的权限...
        analyzeConstantPer(_hasToken, constantMenus, constantRoutes, constantButtons)
        constantRoutes.forEach(route => {
          router.addRoute(route)
        })
        // 仅登陆后才会获取动态权限信息
        if (_hasToken) {
          // 异步获取菜单信息
          Promise.all([fetchData(), getCurrentUserInfo()]).then(([res, res1]) => {
            let data = res.data
            // 解析菜单信息,这里只是获取了动态的菜单,路由,权限
            analyzeDynamicPer(data, dynamicMenus, dynamicRoutes, dynamicButtons, 0)
            // 构建路由表
            dynamicRoutes.forEach(route => {
              try {
                router.addRoute("home", route)
              } catch (err) {
                console.error('菜单添加失败', err, route)
              }
            })
            context.commit('setMenus', [...dynamicMenus, ...constantMenus])
            context.commit('setButtons', {...dynamicButtons, ...constantButtons})
            resolve()
          }, _ => {
            reject()
          }).finally(_ => {
            router.addRoute('home', {
              // 整个系统登陆后的登陆页面登陆后默认访问的是首页,登陆前不可访问
              path: '*',
              redirect: store.getters['system/homePage']
            })
            router.addRoute({
              // 整个系统登陆后的登陆页面登陆后默认访问的是首页,登陆前不可访问
              path: '*',
              redirect: store.getters['system/homePage']
            })
            context.commit('setPerCompleted', true)
          })
        } else {
          context.commit('setPerCompleted', true)
          resolve()
        }
      })
    },
    // 清空权限信息,用于退出登陆的功能
    clear(state) {
      Object.assign(state, stateBuilder())
      // context.replaceState(stateBuilder()) 这个方法无法使用,replaceState是替换store的根状态
    },
    // 关闭tab
    closeTab(context, route) {
      let index = context.state.openedRoutes.findIndex(e => route.meta.code === e.meta.code)
      let length = context.state.openedRoutes.length
      if (index === -1) {
        throw Error("未找到已打开的路由信息")
      }
      if (context.state.activeRoute.meta.code === route.meta.code) {       // 如果是关闭当前页面
        if (length === 1) { // 如果只有一个tab页
          if (isHomePage(route)) { // 如果是首页,那么无需处理
            return
          } else { // 如果不是首页,那么跳转到首页
            // 移除当前的tab
            context.state.openedRoutes.splice(index, 1)
            router.push('/home/homePage')
          }
        } else {
          if (index === length - 1) {
            // 如果关闭的tab在最右侧,那么跳转到左侧的tab
            router.push(context.state.openedRoutes[index - 1])
          } else {
            // 不是最右侧的,那么跳转到右侧的tab
            router.push(context.state.openedRoutes[index + 1])
          }
          // 移除当前tab
          context.state.openedRoutes.splice(index, 1)
        }
      } else {
        // 直接删除tab即可
        context.state.openedRoutes.splice(index, 1)
      }
      context.commit('delCacheRoutes', [route])
    },
    openTab(context, route) {
      context.commit('addOpenedRoutes', route)
      context.commit('addCachedRoutes', route)
    },
    // 关闭全部tab
    closeTabAll(context) {
      let closedRoutes = []
      context.state.openedRoutes = context.state.openedRoutes.filter(e => {
        if (isHomePage(e)) {
          return true
        } else {
          closedRoutes.push(e)
          return false
        }
      })
      context.commit('delCacheRoutes', closedRoutes)
      if (!isHomePage(context.state.activeRoute)) {
        router.push('/home/homePage')
      }
    },
    // 关闭除当前的所有tab
    closeTabAllExpect(context, route) {
      let closedRoutes = []
      // 如果当前路由和选择的路由不一致,要跳转到对应的页面
      if (context.state.activeRoute.meta.code !== route.meta.code) {
        router.push(route)
      }
      context.state.openedRoutes = context.state.openedRoutes.filter(e => {
        if (e.meta.code === route.meta.code) {
          return true
        } else {
          closedRoutes.push(e)
          return false
        }
      })
      context.commit('delCacheRoutes', closedRoutes)
    },
  }
}

function fetchData() {
  return userApi.getMenuTree({group: menuGroup.enum.PC.value})
}

function getCurrentUserInfo() {
  return new Promise((resolve, reject) => {
    if (store.state.user.hasFetchUserInfo) {
      return
    }
    userApi.getDetail().then(res => {
      store.commit('user/setCurrentUserInfo', res.data)
      cache.setCurrentUserInfo( res.data)
      store.commit('user/setHasFetchUserInfo', true)
      if (res.data.workbench) {
        store.commit('system/setDefaultPath', res.data.workbench)
      }
      resolve()
    }, err => {
      console.error('当前用户信息获取失败', err)
      cache.removeCurrentUserInfo()
      reject()
    })
  })
}

function analyzeDynamicPer(data, menus, routes, buttons, level, path = []) {
  if (Array.isArray(data) && data.length) {
    data.sort((e1, e2) =>
      // 根据sort字段升序排序
      // sort字段中支持数字和字符串,***如果sort为null,那么排到最后***
      e1.sort - e2.sort
    )
    data.forEach(e => {
      // todo 解决前端与后端字段不一致的问题,该问题暂时已解决,这里仅做记录
      // e.code = e.router
      // e.path = e.routerName
      // 初步判断一下层级是否正确:每个节点的type必然是不可能高于父type的(仅目录可以等于).
      if (level < e.type || (level === e.type && e.type === menuTypeEnum.MENU.value)) {
        let menu = {}
        let route = {}
        // 如果是目录,加入到菜单表中
        if (e.type === menuTypeEnum.MENU.value && e.available !== false) {
          if (e.visible !== yesOrNo.enum.YES.value) {
            if (Array.isArray(e.children)) {
              e.children.forEach(e1 => {
                e1.visible = false
              })
            }
          } else {
            menu = {
              id: e.id,
              name: e.name,
              icon: e.icon,
              children: [],
              type: e.type,
            }
            menus.push(menu)
          }
          // 递归解析子结构
          path.push(e.name)
          analyzeDynamicPer(e.children, menu.children || [], routes, buttons, e.type, path)
          path.pop()
        } else if (e.type === menuTypeEnum.ROUTE.value && e.available !== false) {
          let $route = dynamicRoutes.find(d => d.code === e.code)
          // 判断路由是否被找到
          if (!($route || ALLOW_INVALID_MENU)) {
            // console.error('找不到code为' + e.code + '的路由!')
            return
          }
          path.push(e.name)
          // 如果visible不为false,那么加入到菜单中
          if (e.visible !== yesOrNo.enum.NO.value) {
            menu = {
              id: e.id,
              name: e.name,
              path: e.path,
              icon: e.icon,
              type: e.type,
            }
            menus.push(menu)
          }
          route = {
            code: e.code,
            path: e.path,
            ...$route,
          }
          route.meta = {
            name: e.name,
            code: e.code,
            id: e.id,
            path: Array.from(path),
            ...$route.meta
          }
          // 加入到路由列表中
          routes.push(route)
          buttons[e.code] = []
          // 路由下的权限按钮也在这里处理,不单独判断了
          if (Array.isArray(e.children) && e.children.length) {
            e.children.forEach(button => {
              if (button.type === menuType.enum.BUTTON.value) {
                buttons[e.code].push({
                  id: button.id,
                  name: button.name,
                  permission: button.permission
                })
              } else {
                console.error('该菜单的类型应为按钮!', button)
              }
            })
          }
          // 递归解析子结构
          analyzeDynamicPer(e.children, menu.children, routes, buttons, e.type, path)
          path.pop()

        } else if (e.type === menuTypeEnum.BUTTON.value && e.available !== false) {
        }
      }
    })
  }
}

// 解析固定权限...
// 目前仅考虑到路由,菜单和按钮暂不做管控
function analyzeConstantPer(hasToken, menus, routes, buttons,) {
  // 如果已经登陆
  if (hasToken) {
    let data = []
    constantRoutes.forEach(route => {
      if ((route.accessible >> 1) % 2) {
        routes.push(route)
      }
    })
  } else {
    // 如果没有登陆,那么只有固定路由
    constantRoutes.forEach(route => {
      if (route.accessible % 2) {
        routes.push(route)
      }
    })
  }
}
